home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 031a / flcpp2.zip / FLEXLIST.DOC < prev    next >
Text File  |  1990-12-06  |  39KB  |  853 lines

  1.  
  2.  
  3.  
  4.                                  FlexList II  for C++
  5.  
  6.  
  7.                                     Copyright 1990
  8.                                     John W. Small
  9.                                  All rights reserved
  10.  
  11.                                  PSW / Power SoftWare
  12.                                     P.O. Box 10072
  13.                              McLean, Virginia 22102 8072
  14.                                     (703) 759-3838
  15.  
  16.                                        11/28/90
  17.  
  18.  
  19.  
  20.                            CLAIM TO PROPRIETARY TECHNIQUES
  21.  
  22.           Several features  of FlexList  used in combination  make FlexList
  23.           unique and  versatile.   The  hybrid stack-queue-list-array  data
  24.           structure  and the techniques used  to implement it  as a generic
  25.           polymorphic  object  can  be  easily  ported  to  other  computer
  26.           languages  and remain intact in their essence.  The author claims
  27.           all rights to these features.
  28.  
  29.  
  30.                                    SHAREWARE NOTICE
  31.  
  32.           This FlexList packet is offered to you as "shareware" meaning try
  33.           before you  buy.  The  shareware version  allows you to  test the
  34.           product to see  if it's suitable for your purposes.   In order to
  35.           legally use FlexList for  any other purpose than to  evaluate it,
  36.           you must first license it from PSW / Power SoftWare by sending in
  37.           a registration fee of $79.95.  Upon registration you will receive
  38.           a printed version of the complete manual and source code.
  39.  
  40.  
  41.                                    SHAREWARE MANUAL
  42.  
  43.           The shareware documentation that follows has been taken  from the
  44.           actual printed FlexList manual.  I've include only the most vital
  45.           information.  Refer to  flexlist.hpp for FlexList member function
  46.           prototypes.
  47.  
  48.  
  49.  
  50.  
  51.  
  52.                      Introduction
  53.  
  54.           FlexList II  is a lot  more than  just a ready-to-run  C++ linked
  55.           list.        It's   a    searchable-sortable-implodable   generic
  56.           heterogeneous-homogeneous      hybrid      stack-queue-list-array
  57.           accessible by value, reference or node.
  58.  
  59.           Anytime your C++ application requires  a stack, queue, or  linked
  60.           list, simply include  flexlist.hpp in your  source code and  then
  61.           start defining your stack,  queue, and/or list variables as  type
  62.           FlexList.   A  FlexList can  be initialized,  by constructor,  to
  63.           store any type of data and then accessed as a stack, queue, list,
  64.           or even an array interchangeably!
  65.  
  66.           With more than 30  FlexList member functions to choose  from, you
  67.           can push, pop, insert,  delete, sort, store, recall, or  find, to
  68.           name but a few.  Access your data by value (copy) or by reference
  69.           (pointer).  Or  move nodes directly  between FlexLists.   Because
  70.           FlexList member functions adjust automatically to different types
  71.           of data, new sets of primitives needn't be derived to accommodate
  72.           new data types.   Thus  your application's coding  time and  code
  73.           size won't continue to grow when you add new types of  FlexLists.
  74.           A FlexList can even be made to accommodate heterogeneous data via
  75.           its virtual member function hooks.
  76.  
  77.           With FlexList you can  quickly construct lists of lists  or other
  78.           composite structures.  And since FlexLists are initialized at run
  79.           time,  the data they hold or even their creation can be specified
  80.           at  run time  thus allowing  your application  new dimensions  of
  81.           adaptability to user inputs.  
  82.  
  83.           Use  FlexList to  code your  next  application's linked  lists in
  84.           minutes  instead  of  days,   without  the  usual  debugging  and
  85.           documenting headaches associated with custom coding  various list
  86.           types.  It's no problem  modifying your application in  midstream
  87.           to incorporate various and differing list types; with FlexList no
  88.           linked  list code needs  to be scrapped  or rewritten.   The code
  89.           space you'll save over cloning list primitives for different data
  90.           types  may just save you  from having to  go the overlay/swapping
  91.           route.
  92.  
  93.  
  94.  
  95.  
  96.  
  97.  
  98.           Chapter  2.    Programming with FlexList
  99.  
  100.  
  101.           This  chapter is a  combination of a brief  tutorial on using the
  102.           FlexList tool  and a  logical survey of  the FlexList  functions.
  103.           You  may find it useful  to lookup the  FlexList functions in the
  104.           reference chapter while reading the example programs here.  Don't
  105.           worry too  much about the  details for  now.  Instead  you should
  106.           finish this chapter with 
  107.  
  108.           1)   an  idea of  the points  to remember  when programming  with
  109.                FlexList, 
  110.  
  111.           2)   a  conceptual model  of FlexList's  hybrid stack-queue-list-
  112.                array data structure, and
  113.  
  114.           3)   an  appreciation for the various ways that a FlexList can be
  115.                manipulated and accessed, namely: by value, by reference, or
  116.                by node.
  117.  
  118.           After  programming for a while  with FlexList, be  sure to reread
  119.           this chapter.
  120.  
  121.           Let's first cover  several points  that you should  keep in  mind
  122.           when using FlexList in any application.
  123.  
  124.           1.   Include flexlist.hpp in any application using FlexList.  
  125.  
  126.                     #include <flexlist.hpp>
  127.  
  128.           2.   Define your stack, queue, or list as a  FlexList, specifying
  129.                the size of the data it is to hold.  To construct a FlexList
  130.                for stack of integers the code is:
  131.  
  132.                     FlexList intStack(sizeof(int));
  133.  
  134.           3.   The address of your  data must be passed to  FlexList member
  135.                functions.  Remember, don't pass the data by value.
  136.  
  137.                     for (int i = 1; i < 11; i++)
  138.                          intStack.pushD(&i);   // address of i
  139.  
  140.           4.   FlexList member  functions return  pointers or integers.   A
  141.                returned value of zero indicates failure of  the function to
  142.                carry out its task.
  143.  
  144.                     while (intStack.popD(&i))  // loop until false
  145.                          cout << i << "\n";
  146.  
  147.  
  148.  
  149.  
  150.  
  151.           5.   Don't forget to link your application with the object module
  152.                created by  compiling flexlist.cpp  or with the  library you
  153.                build.
  154.  
  155.           Let's see the whole program.
  156.  
  157.  
  158.                #include <iostream.h>  // cout
  159.                #include <flexlist.hpp>
  160.  
  161.                main()  //  Count backwards from ten via a stack. 
  162.                {
  163.                     FlexList intStack(sizeof(int));
  164.  
  165.                     for (int i = 1; i < 11; i++)
  166.                          intStack.pushD(&i);
  167.                     while (intStack.popD(&i))
  168.                          cout << i << "\n";
  169.                }
  170.  
  171.  
  172.           Let's proceed with a survey of FlexList member functions.
  173.  
  174.  
  175.  
  176.                       FlexList Constructor/Destructor Functions
  177.  
  178.  
  179.           The FlexList class has two constructors and a virtual destructor.
  180.  
  181.  
  182.                FlexList(size_t sizeofNodeData, unsigned maxNodes
  183.                     = FLmaxMaxNodes);
  184.  
  185.                FlexList(unsigned sizeofCell, unsigned cells,
  186.                     const void *array);
  187.  
  188.                int   clear(); // discards all FlexNodes in FlexList
  189.  
  190.                virtual ~FlexList() { clear(); }
  191.  
  192.  
  193.           The first constructor you have already seen.  It  has a defaulted
  194.           second parameter that  lets you set an upper  limit on the number
  195.           of FlexNodes the FlexList  is allowed to hold.   FLmaxMaxNodes is
  196.           defined  in flexlist.hpp as the maximum value an unsigned int can
  197.           obtain.
  198.  
  199.  
  200.  
  201.  
  202.  
  203.           What's  not obvious  is  if you  construct  a FlexList  with  the
  204.           sizeofNodeData  parameter  equal  to zero  you  bring  FlexList's
  205.           virtual  functions into play that allow the FlexList to work with
  206.           variant data.  The  virtual functions in the FlexList  base class
  207.           are  set  up to  work  with  strings.   Let's  say  you code  the
  208.           following:
  209.  
  210.  
  211.                #define FLvariantData  0
  212.                #define FLstrings FLvariantData
  213.  
  214.                FlexList strStack(FLstrings);
  215.  
  216.  
  217.           (FLvariantData and  FLstrings are defined in  flexlist.hpp.)  The
  218.           FlexList will now work with strings.  The FlexNodes will  be just
  219.           big enough  to hold strings within.   If you derive  a class from
  220.           FlexList  and override  the virtual  functions then  your derived
  221.           class can accommodate any type of  object you want it to (see the
  222.           FlexList constructor entry in the reference chapter).
  223.  
  224.           The  second constructor allows you to  explode a conventional C++
  225.           array (vector) into a FlexList.
  226.  
  227.           The FlexList destructor  is virtual so that  your derived classes
  228.           can be destructed from code  written to work on FlexLists.   Such
  229.           is the case with composite FlexList structures.
  230.  
  231.  
  232.                            FlexList Header Access Functions
  233.  
  234.           As you become  more familiar  with what's inside  a FlexList  you
  235.           will want to access the data fields inside the FlexList header.  
  236.  
  237.  
  238.                frontD()            currentD()          rearD()
  239.                CurNum()            Nodes()             MaxNodes()
  240.                setMaxNodes()       notFull()           SizeofNodeData()
  241.                isSorted()          unSort()            Compare()
  242.                setCompare()        isFixed()           isVariant()
  243.  
  244.  
  245.           A FlexList  can be accessed as  a stack, queue, list,  or even an
  246.           array once it  has nodes  in it, interchangeably.   The  FlexList
  247.           header keeps track  of everything  so if your  pushing data  onto
  248.           your  "stack" at one moment, you can  recall an element from your
  249.           "array"  the  next.   You can  sort  your FlexList,  then perform
  250.           various other operations on it  and isSorted will tell you if  it
  251.           is still sorted.   You can set  an upper limit  on the number  of
  252.           nodes a FlexList is  allowed to hold with setMaxNodes.   You will
  253.           come to know what each function does with time.
  254.  
  255.  
  256.  
  257.  
  258.  
  259.                           FlexList Stack and Queue Functions
  260.  
  261.           A stack provides LIFO (Last  In, First Out) storage.  A  complete
  262.           set of  stack  primitives is  provided.   These  functions  don't
  263.           disturb  the queue, list, or  array structure of  a FlexList.  In
  264.           other words, you can access your  FlexList as a stack at any time
  265.           and  revert back  to  accessing it  as a  queue,  list, or  array
  266.           freely.
  267.  
  268.  
  269.                pushN()             pushD()             popN()
  270.                popD()              topD()              insQN()
  271.                insQD()             frontD()            rearD()
  272.  
  273.  
  274.           A queue provides FIFO (First In, First Out) storage.  Notice that
  275.           some  of the stack functions  double up here  as queue functions,
  276.           e.g. popD, topD.  Also I have again included some of the FlexList
  277.           header  access  functions, i.e.  frontD  and  rearD which  return
  278.           pointers  to the data in  the first and  last nodes respectively.
  279.           Basically  I'm  suggesting  various  logical  ways  to categorize
  280.           FlexList functions to help  you remember them.  You'll  find that
  281.           several functions may belong in multiple categories.
  282.  
  283.  
  284.  
  285.  
  286.  
  287.           The functions  ending with "N"  work directly with  the FlexNodes
  288.           which  contain your data.  For an  example, suppose that you want
  289.           to pop your  stack directly into your queue.   The following code
  290.           shows how.
  291.  
  292.  
  293.                #include  <iostream.h>        // cout
  294.                #include  <flexlist.hpp>
  295.  
  296.                int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  297.                int *iptr;
  298.                #define  inT0   ((int *)0)
  299.  
  300.                main()         /*  count to ten the hard way  */
  301.                {
  302.                     FlexList s(sizeof(a[0]),sizeof(a)/sizeof(a[0]),a);
  303.                     FlexList q(s.SizeofNodeData());
  304.                     while ((iptr = (int *) q.insQN(s.popN())) != inT0)
  305.                          cout << *iptr << "\n";
  306.                }
  307.  
  308.  
  309.           In  this example the stack is constructed by "exploding" an array
  310.           of integers into a  FlexList.  Next the  queue is constructed  to
  311.           hold the  same size data as the stack.   Then the stack is popped
  312.           directly into  the queue and a  pointer to the data  in the newly
  313.           inserted  queue  node  is  captured  and  tested  to  control the
  314.           looping!   I print the  integer each time so you  can see that it
  315.           made it into  the queue.  Did  you notice how I  defined the NULL
  316.           integer pointer?  I did that here so you'll know  what's going on
  317.           when you see other NULL pointers elsewhere.
  318.  
  319.  
  320.                                FlexList List Functions
  321.  
  322.           Any  FlexList  can be  treated as  a  doubly linked  list thereby
  323.           providing  sequential storage.   You  can insert nodes  or delete
  324.           them.   The FlexList header maintains a current node pointer that
  325.           lets the list functions  know where the insertion or  deletion is
  326.           to  take place.   Stack  and queue  functions don't  disturb this
  327.           current  pointer unless of course  it points to  the top/front of
  328.           the  stack/queue and that node  is popped/removed.   In that case
  329.           the current node becomes undefined.
  330.  
  331.  
  332.                mkcur()             insN()              insD()
  333.                insSortN()          insSortD()          delN()
  334.                delD()              nextD()             prevD()
  335.                CurNum()            currentD()          Compare()
  336.                setCompare()
  337.  
  338.  
  339.  
  340.  
  341.  
  342.           FlexList  nodes are numbered starting at one.  When nextD reaches
  343.           the  end of the list the current node number is set to zero which
  344.           is said to be undefined and  nextD returns the NULL void pointer.
  345.           On the next  call to nextD the current node  becomes one, that is
  346.           of course  if there are nodes  in the FlexList!   PrevD works the
  347.           same way.   This mechanism  makes it handy  to walk around  lists
  348.           pausing at the ends.  If you want to set the current pointer to a
  349.           particular node, use mkcur.
  350.  
  351.           Oh, I guess I should mention again that you can store any type of
  352.           data in a  FlexList not just integers.   Let's see something like
  353.           that last example again with strings.
  354.  
  355.  
  356.                #include  <iostream.h>        // cout
  357.                #include  <flexlist.hpp>
  358.  
  359.                char *a[] = { "Now is the time", "for all good",
  360.                     "programmers to cut", "their coding time",
  361.                     "with FlexList!"
  362.                };
  363.                char **sptr;
  364.                #define chaRR  char **
  365.                #define chaRR0 (chaRR)0
  366.  
  367.                main()    //  PSW propaganda
  368.                {
  369.                     FlexList l(sizeof(a[0]),sizeof(a)/sizeof(a[0]),a);
  370.                     while ((sptr = (chaRR) l.nextD(0)) != (chaRR0))
  371.                          cout << *sptr << "\n";
  372.                     l.mkcur(l.Nodes());
  373.                     while (l.delD(0))
  374.                          /* null statement */;  //  l.clear();
  375.                     cout << "\nThere should be zero nodes now: ";
  376.                     cout << l.Nodes();
  377.                }
  378.  
  379.  
  380.           In this  program I  exploded a  vector  of char  pointers into  a
  381.           FlexList.  Whenever FlexLists are constructed the current node is
  382.           set  as undefined  so nextD  starts  walking across  the FlexList
  383.           beginning  with the first node.  NextD  will copy the data in the
  384.           next  node to  whatever  address you  specify  for the  parameter
  385.           unless of course it is  the NULL address!  When you  are browsing
  386.           the  reference chapter  you will  notice many  FlexList functions
  387.           that copy data  to/from a FlexNode when an address  is given.  If
  388.           the NULL address is specified the copying action is inhibited but
  389.           the function otherwise performs its purpose.
  390.  
  391.  
  392.  
  393.  
  394.  
  395.           In this example nextD is  inhibited from copying any data  but it
  396.           never the less  moves the  current pointer on  to the next  node.
  397.           NextD  also returns a void pointer to  the data in the next node.
  398.           I capture that pointer in order  to print the string but I'm also
  399.           using it to control the loop.
  400.  
  401.           All FlexList  functions return  either pointers or  integer types
  402.           that  are non zero  only when  the respective  function completes
  403.           successfully.  The void pointers returned from FlexList functions
  404.           point to the user data in focus.  In the case  of nextD it points
  405.           to the  user data in  the next node.   I have simply  type casted
  406.           this pointer to a pointer to the type of data I'm storing  in the
  407.           FlexNodes  in order to gain access to  that data.  As you can see
  408.           FlexList member functions allow  you to access you data  by value
  409.           (copy) or by reference (pointer) as well as moving nodes directly
  410.           between/within FlexLists.
  411.  
  412.           Back to our  example, mkcur moves the current node pointer to the
  413.           last node in the list.  Mkcur also  returns a pointer to the data
  414.           in the last node  but I choose to ignore it.  Now delD is used to
  415.           delete the  nodes from the  list.  DelD removes  the current node
  416.           after  copying its contents to the  address specified (copying is
  417.           inhibited here by the NULL address) and then unlinks the FlexNode
  418.           from the  FlexList  and  proceeds to  deallocate  it  making  the
  419.           previous node in the FlexList the  new current node.  I might add
  420.           that  insD does the exact  opposite, i.e. inserts  a new FlexNode
  421.           after the current  node making the  new node current.   Again the
  422.           stack  and queue structure of FlexList is undisturbed by any list
  423.           functions invoked on the FlexList and vice versa.
  424.  
  425.  
  426.                             FlexList Search/Sort Functions
  427.  
  428.           The Search/Sort  functions allow you  to lookup and/or  sort your
  429.           data.  Every FlexList has a user definable compare function.  Use
  430.           setCompare to set a FlexList's internal compare function pointer.
  431.           To facilitate  sorting define your compare function to return -1,
  432.           0, or 1 to indicate whether the first data being compared is less
  433.           than,  equal to, or greater  than the second,  respectively.  The
  434.           compare  function is  also  used for  matching  in the  find...()
  435.           functions.  Please note that most of the functions mentioned here
  436.           modify the current node setting, thus they interact with the list
  437.           functions mentioned earlier.
  438.  
  439.  
  440.                insSortN()          insSortD()          findFirstD()
  441.                findNextD()         findLastD()         findPrevD()
  442.                sort()              isSorted()          unSort()
  443.                Compare()           setCompare()
  444.  
  445.  
  446.  
  447.  
  448.  
  449.           Use insSortD/N() to perform  insertion sorts.  If the  list isn't
  450.           sorted then  sort will be called  automatically before attempting
  451.           the insertion.  If  a compare function pointer hasn't  been setup
  452.           then the insertion is aborted.
  453.  
  454.           The find...D functions  work regardless if the FlexList is sorted
  455.           or not.  If it is sorted then the binary search algorithm is used
  456.           to find the first/last matching data  and a linear search is used
  457.           to find  the next/previous  match stopping immediately  after the
  458.           first mismatch.   If the  FlexList is not sorted  then the linear
  459.           search algorithm is used to find the first/last matching data and
  460.           again to find the  next/previous match stopping only at  the ends
  461.           of the list.
  462.  
  463.           Use sort or setCompare to setup the compare function pointer.  If
  464.           the  NULL  compare  function   pointer,  FLcompare0  (defined  in
  465.           flexlist.hpp),  is  passed  to  sort then  the  previous  compare
  466.           function  pointer is  used to  sort the  list.  Call  isSorted to
  467.           determine  whether a FlexList is still sorted from its last sort.
  468.           For example, suppose you sort  a list and pop some nodes  off the
  469.           front.   Well that won't  cause the  FlexList to  be unsorted  so
  470.           isSorted will  return true.   But if you  push some data  onto it
  471.           treating  it like a  stack, that may  or may not  ruin the sorted
  472.           order.    IsSorted will  return false  because  it can  no longer
  473.           guarantee that  the FlexList is sorted.   You need to  be careful
  474.           though since  nextD,  prevD, and  mkcur won't  cause isSorted  to
  475.           reset to false  even though you  might have modified the  data in
  476.           the FlexNode via the returned void pointer!  In that case you may
  477.           want  to call  unSort to  reset isSorted  so that it  will return
  478.           false.
  479.  
  480.           The following example performs an unsorted linear search followed
  481.           by an alphabetical sort.
  482.  
  483.  
  484.                #include  <iostream.h>        // cout
  485.                #include  <string.h>          // strstr, strcmp
  486.                #include  <flexlist.hpp>
  487.  
  488.                int strStr(char *s, char *t)
  489.                {
  490.                     return !(int)strstr(s,t);
  491.                }
  492.  
  493.                main()
  494.                {
  495.                     FlexList l(FLstrings);
  496.                     char *s, sbuf[80];
  497.                     char *mask = "overtime";
  498.  
  499.  
  500.  
  501.  
  502.  
  503.                     l.insD("Once upon a time there were three");
  504.                     l.insD("programmers, who worked");
  505.                     l.insD("allot of overtime!");
  506.                     l.insQD("That was before the FlexList Fox");
  507.                     l.insQD("joined the staff!");
  508.                     for (l.mkcur(0); l.nextD(sbuf);/* no reinit */)
  509.                          cout << "\n Node: " << l.CurNum() << ". " << sbuf;
  510.                     l.setCompare(FLcomparE(strStr));
  511.                     if ((s = (char *)l.findFirstD(mask)) != (char *)0)  {
  512.                          cout << "\n Mask: \"" << mask << "\"";
  513.                          cout << " found in node: " << l.CurNum();
  514.                          cout << ". " << s;
  515.                     }
  516.                     l.sort(FLcomparE(strcmp));
  517.                     for (unsigned i = 1; l.recallD(sbuf,i); i++)  {
  518.                          cout << "\n Node: " << l.CurNum();
  519.                          cout << ". " << sbuf;
  520.                     }
  521.                }
  522.  
  523.  
  524.           This program  constructs a variant  FlexList.   The FlexNodes  in
  525.           this  FlexList are only be  enough to hold  the character strings
  526.           passed as parameters (please note that character string constants
  527.           are pointers to the strings so  I didn't use the address of, "&",
  528.           operator!)  I didn't use the second constructor because it builds
  529.           fixed size FlexNode (homogeneous) FlexLists - an array has  fixed
  530.           cell sizes.  Instead I inserted the strings one by one and queued
  531.           the last two just to be different.
  532.  
  533.           The first "for  loop" uses nextD  to verify  the contains of  the
  534.           FlexNodes.   NextD  only copies  the  string and  zero terminator
  535.           thanks to  the virtual functions (see  FlexList constructor entry
  536.           in the  reference chapter  to see  how to  construct heterogenous
  537.           lists).   Be sure  that the  variable whose  address you pass  to
  538.           nextD is big  enough to accommodate the largest data  that can be
  539.           read!   You should have noticed  that I had to use mkcur(0) since
  540.           the  current  node pointer  is still  pointing  to the  last node
  541.           inserted and not the last node queued.  Remember, queue functions
  542.           don't  disturb the list structure  - the current  node concept is
  543.           part of the list structure, not the queue structure!
  544.  
  545.           Since the list  is not  sorted, findFirstD searches  in a  linear
  546.           fashion  starting with  the  first node,  internally calling  the
  547.           compare  function setup  with setCompare.   The  FLcomparE macro,
  548.           defined  in  flexlist.hpp,  type  casts  strStr  to  the  precise
  549.           function pointer type required  by both setCompare and sort.   My
  550.           strStr  returns 0 if t is  within s.  Since  only a linear search
  551.           will be used with  this compare function, it doesn't  matter that
  552.           is doesn't return -1 or 1 to indicate less than or greater than.
  553.  
  554.  
  555.  
  556.  
  557.  
  558.           The program  proceeds with a  standard alphabetical sort  and the
  559.           resultant  ordering is  displayed with  recallD, an  array access
  560.           function which you'll see in the next section.
  561.  
  562.  
  563.                                FlexList Array Functions
  564.  
  565.           An  array provides randomly  accessible storage.   A FlexList can
  566.           also be accessed as an array once it has nodes in it.
  567.  
  568.  
  569.                storeD()            recallD()           mkcur()
  570.                currentD()          CurNum()
  571.  
  572.  
  573.           The  last node  accessed  becomes the  new  current node.    When
  574.           randomly accessing a FlexList, mkcur is called internally by both
  575.           storeD and recallD  to make  the requested node  current.   Mkcur
  576.           determines which  pointer (front, current, or rear) is closest to
  577.           the  requested node.  It then follows the FlexList's linkage from
  578.           that  closest pointer to the  newly requested node.   The current
  579.           pointer  is left positioned  at the new  node.  Please  note that
  580.           array,  search/sort, and list functions interact in that they all
  581.           work  with and modify the current node  setting.  Stack and queue
  582.           functions are independent, however.
  583.  
  584.  
  585.                             FlexList Compaction Functions
  586.  
  587.           Sometimes you  want to work  with a  list, other times  it's more
  588.           convenient  to work with an array.  Although FlexList allows this
  589.           chameleon behavior, your application  may progress in stages that
  590.           favor  a  linked  list at  one  point  and  a conventional  array
  591.           (vector)  at another.   FlexList  has "compaction"  functions for
  592.           converting  a FlexList into  a conventional array  or vice versa,
  593.           thus   allowing  you   to  optimize   the  performance   of  your
  594.           application.
  595.  
  596.  
  597.                          FlexList()          pack()
  598.                          packPtrs()
  599.  
  600.  
  601.  
  602.  
  603.  
  604.           You can think of  the second FlexList constructor as  exploding a
  605.           conventional array into  a FlexList.   Think of  the pack  member
  606.           function as doing the exact opposite or imploding a FlexList into
  607.           a conventional array.  Arrays compacted by pack and packPtrs must
  608.           be explicitly deleted with a call to delete when no longer needed
  609.           if their memory  is ever  to be recovered  for subsequent  reuse.
  610.           PackPtrs returns an array  of void pointers pointing to  the data
  611.           in  the FlexNodes.  This  array is NULL  terminated to facilitate
  612.           subsequent processing.
  613.  
  614.           For  the  last  example program  we'll  clone  a  vector of  char
  615.           pointers but the clone will have the advantage over its parent of
  616.           being sorted in alphabetical order.
  617.  
  618.  
  619.                #include  <iostream.h>        // cout
  620.                #include  <string.h>          // strcmp
  621.                #include  <flexlist.hpp>
  622.  
  623.                char *a[] = { "one", "two", "three", "four", "five" };
  624.                char **A;
  625.  
  626.                int strCmp(char **s, char **t)
  627.                {
  628.                     return strcmp(*s,*t);
  629.                }
  630.  
  631.                main()
  632.                {
  633.                     FlexList l(sizeof(a[0]),sizeof(a)/sizeof(a[0]),a);
  634.                     l.sort(FLcomparE(strCmp));
  635.                     A = (char **) l.pack();
  636.                     for (int i = 0; i < sizeof(a)/sizeof(a[0]); i++)
  637.                          cout << "\n a[" << i << "] = " << a[i];
  638.                     if (A)  {
  639.                          for (i = 0; i < l.Nodes(); i++)
  640.                               cout << "\n A[" << i << "] = " << A[i];
  641.                          delete A;
  642.                     }
  643.                }
  644.  
  645.  
  646.           Remember that the FlexNodes in this program contain char pointers
  647.           and  that the  compare function  is passed  pointers to  the char
  648.           pointers, that is why the strCmp has to dereference them.
  649.  
  650.  
  651.  
  652.  
  653.  
  654.           Many  commercial  toolbox  functions require  vector  parameters.
  655.           With FlexList's  compaction functions you can  manipulate vectors
  656.           on the  fly.  The  vectors can be stored  in files and  loaded as
  657.           needed via a  FlexList and  subsequent packing.   The vector  can
  658.           then be kept around only during the computation phase in which it
  659.           is  needed.    Large,  oversized,  static  vectors  need  not  be
  660.           allocated  at compile  time to  cope with  worst case  scenarios,
  661.           consequently consuming  precious data segment  space within  your
  662.           program.
  663.  
  664.  
  665.                           Accessing FlexList Nodes and Data
  666.  
  667.           Now that we've finished categorizing FlexList functions along the
  668.           lines  of  its  hybrid  stack-queue-list-array  structure,  let's
  669.           rethink  what we've  seen  in  terms  of  how  the  FlexList  was
  670.           accessed,  namely: by  value, by  reference, and  by node.   This
  671.           gives us a second way to analyze FlexList functions.
  672.  
  673.           "By value" implies that the data is copied to or from a FlexNode.
  674.           For example,  with popD the top  node of the stack  is popped and
  675.           the  data is  copied to  the address  specified by  the parameter
  676.           before the node is  freed and returned  to the heap.   We are  in
  677.           effect  accessing the data in the top  node by value since we are
  678.           retrieving, in actuality, a copy of it.
  679.  
  680.                     popD(&i);   // i is same type in FlexNode
  681.  
  682.           "By  reference" implies that the data in the FlexNode is accessed
  683.           by pointer.   You will need  to type cast these  void pointers to
  684.           pointers to the  type of data you  have stored in the  FlexNodes.
  685.           Suppose we're walking backward across a FlexList of integers with
  686.           the code:
  687.  
  688.                     while ((iptr = (int *)l.prevD(0)) != (int *)0)
  689.                          cout "\n" << *iptr;
  690.  
  691.           All void  pointers returned by  FlexList functions point  to user
  692.           data.   Thus the data  can be modified  directly.  "By reference"
  693.           functions  are provided to speed up  processing.  Without pointer
  694.           access you would have to first copy the data out of the FlexNode,
  695.           modify it and then copy it back.  With large data structures that
  696.           could  prove to be quite inefficient.   Please note the nextD and
  697.           prevD are purely "by reference" when called with their parameters
  698.           equal  to  the NULL  address.   Actually  all  FlexList functions
  699.           returning   void   pointers  allow   access  "by   reference"  in
  700.           combination perhaps with "by value" access.
  701.  
  702.  
  703.  
  704.  
  705.  
  706.       In  queuing  network  simulations you  will  want  to  move nodes
  707.           between FlexLists  rapidly.  Without  access "by node"  you would
  708.           have  to  "popD" the  source  queue and  "insQD"  the destination
  709.           queue.   This would  entail copying the data  from the front node
  710.           into   a  local  variable   of  the  same   type,  unlinking  and
  711.           deallocating the  FlexNode, then reallocating a  new FlexNode and
  712.           linking it into the other queue and finally copying the data from
  713.           the local  variable back into  the node.   The faster  way is  to
  714.           unlink  the FlexNode from the source queue and relink it directly
  715.           into the destination queue, e.g.
  716.  
  717.                     dstQ.insN(srcQ.popN());
  718.  
  719.           If dstQ is already full then the node popped from srcQ is lost in
  720.           the  twilight zone.   A better approach  would be  to prevent the
  721.           chance of FlexNodes being left dangling:
  722.  
  723.                     while (dstQ.notFull() && srcQ.Nodes())
  724.                          dstQ.insN(srcQ.popN());
  725.  
  726.           The  "By node"  functions  unlink and  relink FlexNodes  directly
  727.           between  compatible FlexLists.   Compatible  in this  sense means
  728.           that  both  FlexLists  have   equal  sizeofNodeData  fields  (not
  729.           necessarily  initialized for  the  same data  type)  .   Use  the
  730.           SizeofNodeData function  to read  the sizeofNodeData field.   Two
  731.           FlexLists could also be  considered to be compatible if  they are
  732.           both  variant FlexLists with compatible data.  I should point out
  733.           that  variant FlexLists  have  the sizeofNodeData  fields set  to
  734.           zero.  Be careful not to assume that two FlexLists are compatible
  735.           just because both sizeofNodeData  fields are equal to zero.   You
  736.           are responsible for insuring  that your FlexLists are compatible.
  737.           Remember also, FlexNodes unlinked with a function ending with "N"
  738.           must be relinked with a function ending with "N" to a  compatible
  739.           FlexList or otherwise explicitly disposed of.
  740.  
  741.  
  742.                                        Summary
  743.  
  744.           Let's review what we learned starting with the points to remember
  745.           when programming with the FlexList tool.
  746.  
  747.                1.   Be sure to  include the FlexList  header in any  module
  748.                     that references FlexList functions.
  749.  
  750.                2.   Define  your stacks, queues, lists, etc. as "FlexList".
  751.                     Define your dynamic versions as  pointers to FlexLists,
  752.                     i.e. "FlexL".
  753.  
  754.                3.   If the function is somehow involved with the copying of
  755.                     user data, the address of the data is always passed.
  756.  
  757.  
  758.  
  759.  
  760.  
  761.                4.   All FlexList member functions return either pointers or
  762.                     integers.   A returned value of  zero indicates failure
  763.                     of the function to complete its task.
  764.  
  765.                5.   Link your application with the compiled flexlist object
  766.                     module or the flexlist library you build.
  767.  
  768.  
  769.           Next,  let's  review  the  various  functions  available  in  the
  770.           FlexList tool.   FlexList functions can  be categorized according
  771.           to  the logical  nature of  a FlexList's  inherent hybrid  stack-
  772.           queue-list-array structure.
  773.  
  774.  
  775.                            FlexList Constructor/Destructors
  776.  
  777.                FlexList()          FlexList()          clear()
  778.                ~FlexList()
  779.  
  780.  
  781.                            FlexList Header Access Functions
  782.  
  783.                frontD()            currentD()          rearD()
  784.                CurNum()            Nodes()             MaxNodes()
  785.                setMaxNodes()       notFull()           SizeofNodeData()
  786.                isSorted()          unSort()            Compare()
  787.                setCompare()        isFixed()           isVariant()
  788.  
  789.  
  790.                           FlexList Stack and Queue Functions
  791.  
  792.                pushN()             pushD()             popN()
  793.                popD()              topD()              insQN()
  794.                insQD()             frontD()            rearD()
  795.  
  796.  
  797.                                FlexList List Functions
  798.  
  799.                mkcur()             insN()              insD()
  800.                insSortN()          insSortD()          delN()
  801.                delD()              nextD()             prevD()
  802.                CurNum()            currentD()          Compare()
  803.                setCompare()
  804.  
  805.  
  806.  
  807.  
  808.  
  809.                             FlexList Search/Sort Functions
  810.  
  811.                insSortN()          insSortD()          findFirstD()
  812.                findNextD()         findLastD()         findPrevD()
  813.                sort()              isSorted()          unSort()
  814.                Compare()           setCompare()
  815.  
  816.  
  817.                                FlexList Array Functions
  818.  
  819.                storeD()            recallD()           mkcur()
  820.                currentD()          curNum()
  821.  
  822.  
  823.                             FlexList Compaction Functions
  824.  
  825.                FlexList()          pack()              packPtrs()
  826.  
  827.  
  828.           Finally, FlexLists  can be  accessed "by value",  "by reference",
  829.           and  "by node."    "By value"  entails the  copying of  user data
  830.           between  the FlexNodes  and  user specified  addresses.   If  the
  831.           address specified is NULL  then the copying of data  is inhibited
  832.           but  the function performs otherwise as expected.  The address is
  833.           always the first parameter of the FlexList function requiring it.
  834.           "By  reference" infers  that  user data  is manipulated  directly
  835.           inside  a  FlexNode  via  a  pointer.    All  FlexList  functions
  836.           returning void pointers allow  "by reference" access.  "By  node"
  837.           functions   allow  FlexNodes  to   be  yanked/inserted  from/into
  838.           FlexLists.   These functions are  named with "N"  suffixes.  Move
  839.           FlexNodes   only  between  compatible  FlexLists.    Don't  leave
  840.           FlexNodes  dangling: either  insert them  back into  a compatible
  841.           FlexList with an "N" function or explicitly delete them.
  842.  
  843.  
  844.           By now you  should be ready to start the  planning and subsequent
  845.           coding  of  your  FlexList  application  with  the  help  of  the
  846.           reference chapter  on FlexList functions.   Later, when  you feel
  847.           comfortable  with FlexList,  you will  want to  try your  hand at
  848.           deriving  your   own  variant   FlexLists  (lists  that   contain
  849.           heterogeneous data).   Be sure  to read  the entry for  the first
  850.           FlexList constructor in the  reference chapter for an explanation
  851.           of writing  your own FlexList virtual  functions that accommodate
  852.           your heterogeneous data.
  853.